// Generic version of operations
module.exports = function (SecretShare) {
  /**
   * Checks if the given parameter is a constant, used to determine whether constant or secret
   * operations should be executed when the generic version of an operation is called
   * @method isConstant
   * @memberof module:jiff-client~JIFFClient#SecretShare
   * @instance
   * @param {number/object} o - the parameter to determine.
   * @return {boolean} true if o is a valid constant, false otherwise.
   */
  SecretShare.prototype.isConstant = function (o) {
    return typeof(o) === 'number';
  };

  /**
   * Generic Addition.
   * Uses either the constant or secret version of this operator depending on type of paramter.
   * @method add
   * @memberof module:jiff-client~JIFFClient#SecretShare
   * @instance
   * @param {number|module:jiff-client~JIFFClient#SecretShare} o - the other operand (can be either number or share).
   * @return {module:jiff-client~JIFFClient#SecretShare} this party's share of the result.
   *
   * @example
   * var shares = jiffClient.share(input);
   * // this will add two secret shared values together
   * var sum1 = shares[1].add(shares[2]);
   * // this will add 3 to the secret input from party 1
   * var sum2 = shares[1].add(3);
   * // both sum1 and sum2 are SecretShares
   */
  SecretShare.prototype.add = function (o) {
    if (this.isConstant(o)) {
      return this.cadd(o);
    }
    return this.sadd(o);
  };


  /**
   * Generic Subtraction.
   * Uses either the constant or secret version of this operator depending on type of paramter.
   * @method sub
   * @param {number|module:jiff-client~JIFFClient#SecretShare} o - the other operand (can be either number or share).
   * @return {module:jiff-client~JIFFClient#SecretShare} this party's share of the result.
   * @memberof module:jiff-client~JIFFClient#SecretShare
   * @instance
   */
  SecretShare.prototype.sub = function (o) {
    if (this.isConstant(o)) {
      return this.csub(o);
    }
    return this.ssub(o);
  };


  /**
   * Generic Multiplication.
   * Uses either the constant or secret version of this operator depending on type of paramter.
   * @method mult
   * @param {number|module:jiff-client~JIFFClient#SecretShare} o - the other operand (can be either number or share).
   * @param {string} [op_id=auto_gen()] - the operation id which is used to identify this multiplication (and internally, the corresponding beaver triplet).
   *                         This id must be unique, and must be passed by all parties to the same instruction.
   *                         this ensures that every party gets a share from the same triplet for every matching instruction. An automatic id
   *                         is generated by increasing a local counter, default ids suffice when all parties execute the
   *                         instructions in the same order. Only used if secret multiplication is used.
   * @return {module:jiff-client~JIFFClient#SecretShare} this party's share of the result.
   * @memberof module:jiff-client~JIFFClient#SecretShare
   * @instance
   */
  SecretShare.prototype.mult = function (o, op_id) {
    if (this.isConstant(o)) {
      return this.cmult(o);
    }
    return this.smult(o, op_id);
  };


  /**
   * Generic XOR for bits (both this and o have to be bits to work correctly).
   * Uses either the constant or secret version of this operator depending on type of paramter.
   * @method xor_bit
   * @param {number|module:jiff-client~JIFFClient#SecretShare} o - the other operand (can be either number or share).
   * @param {string} [op_id=auto_gen()] - the operation id which is used to identify this operation.
   *                         This id must be unique, and must be passed by all parties to the same instruction, to
   *                         ensure that corresponding instructions across different parties are matched correctly.
   *                         Only used if secret xor is used..
   * @return {module:jiff-client~JIFFClient#SecretShare} this party's share of the result.
   * @memberof module:jiff-client~JIFFClient#SecretShare
   * @instance
   */
  SecretShare.prototype.xor_bit = function (o, op_id) {
    if (this.isConstant(o)) {
      return this.cxor_bit(o);
    }
    return this.sxor_bit(o, op_id);
  };

  /**
   * Generic OR for bits (both this and o have to be bits to work correctly).
   * Uses either the constant or secret version of this operator depending on type of paramter.
   * @method or_bit
   * @param {number|module:jiff-client~JIFFClient#SecretShare} o - the other operand (can be either number or share).
   * @param {string} [op_id=auto_gen()] - the operation id which is used to identify this operation.
   *                         This id must be unique, and must be passed by all parties to the same instruction, to
   *                         ensure that corresponding instructions across different parties are matched correctly.
   *                         Only used if secret or is used..
   * @return {module:jiff-client~JIFFClient#SecretShare} this party's share of the result.
   * @memberof module:jiff-client~JIFFClient#SecretShare
   * @instance
   */
  SecretShare.prototype.or_bit = function (o, op_id) {
    if (this.isConstant(o)) {
      return this.cor_bit(o);
    }
    return this.sor_bit(o, op_id);
  };

  /**
   * Generic Greater or equal.
   * Uses either the constant or secret version of this operator depending on type of paramter.
   * @method gteq
   * @param {number|module:jiff-client~JIFFClient#SecretShare} o - the other operand (can be either number or share).
   * @param {string} [op_id=auto_gen()] - the operation id which is used to identify this operation.
   *                         This id must be unique, and must be passed by all parties to the same instruction, to
   *                         ensure that corresponding instructions across different parties are matched correctly.
   * @return {module:jiff-client~JIFFClient#SecretShare} this party's share of the result.
   * @memberof module:jiff-client~JIFFClient#SecretShare
   * @instance
   */
  SecretShare.prototype.gteq = function (o, op_id) {
    if (this.isConstant(o)) {
      return this.cgteq(o, op_id);
    }
    return this.sgteq(o);
  };


  /**
   * Generic Greater than.
   * Uses either the constant or secret version of this operator depending on type of paramter.
   * @method gt
   * @param {number|module:jiff-client~JIFFClient#SecretShare} o - the other operand (can be either number or share).
   * @param {string} [op_id=auto_gen()] - the operation id which is used to identify this operation.
   *                         This id must be unique, and must be passed by all parties to the same instruction, to
   *                         ensure that corresponding instructions across different parties are matched correctly.
   * @return {module:jiff-client~JIFFClient#SecretShare} this party's share of the result.
   * @memberof module:jiff-client~JIFFClient#SecretShare
   * @instance
   */
  SecretShare.prototype.gt = function (o, op_id) {
    if (this.isConstant(o)) {
      return this.cgt(o, op_id);
    }
    return this.sgt(o, op_id);
  };


  /**
   * Generic Less or equal.
   * Uses either the constant or secret version of this operator depending on type of paramter.
   * @method lteq
   * @param {number|module:jiff-client~JIFFClient#SecretShare} o - the other operand (can be either number or share).
   * @param {string} [op_id=auto_gen()] - the operation id which is used to identify this operation.
   *                         This id must be unique, and must be passed by all parties to the same instruction, to
   *                         ensure that corresponding instructions across different parties are matched correctly.
   * @return {module:jiff-client~JIFFClient#SecretShare} this party's share of the result.
   * @memberof module:jiff-client~JIFFClient#SecretShare
   * @instance
   */
  SecretShare.prototype.lteq = function (o, op_id) {
    if (this.isConstant(o)) {
      return this.clteq(o, op_id);
    }
    return this.slteq(o, op_id);
  };


  /**
   * Generic Less than.
   * Uses either the constant or secret version of this operator depending on type of paramter.
   * @method lt
   * @param {number|module:jiff-client~JIFFClient#SecretShare} o - the other operand (can be either number or share).
   * @param {string} [op_id=auto_gen()] - the operation id which is used to identify this operation.
   *                         This id must be unique, and must be passed by all parties to the same instruction, to
   *                         ensure that corresponding instructions across different parties are matched correctly.
   * @return {module:jiff-client~JIFFClient#SecretShare} this party's share of the result.
   * @memberof module:jiff-client~JIFFClient#SecretShare
   * @instance
   */
  SecretShare.prototype.lt = function (o, op_id) {
    if (this.isConstant(o)) {
      return this.clt(o, op_id);
    }
    return this.slt(o, op_id);
  };


  /**
   * Generic Equals.
   * Uses either the constant or secret version of this operator depending on type of paramter.
   * @method eq
   * @param {number|module:jiff-client~JIFFClient#SecretShare} o - the other operand (can be either number or share).
   * @param {string} [op_id=auto_gen()] - the operation id which is used to identify this operation.
   *                         This id must be unique, and must be passed by all parties to the same instruction, to
   *                         ensure that corresponding instructions across different parties are matched correctly.
   * @return {module:jiff-client~JIFFClient#SecretShare} this party's share of the result.
   * @memberof module:jiff-client~JIFFClient#SecretShare
   * @instance
   */
  SecretShare.prototype.eq = function (o, op_id) {
    if (this.isConstant(o)) {
      return this.ceq(o, op_id);
    }
    return this.seq(o, op_id);
  };


  /**
   * Generic Not Equals.
   * Uses either the constant or secret version of this operator depending on type of paramter.
   * @method neq
   * @param {number|module:jiff-client~JIFFClient#SecretShare} o - the other operand (can be either number or share).
   * @param {string} [op_id=auto_gen()] - the operation id which is used to identify this operation.
   *                         This id must be unique, and must be passed by all parties to the same instruction, to
   *                         ensure that corresponding instructions across different parties are matched correctly.
   * @return {module:jiff-client~JIFFClient#SecretShare} this party's share of the result.
   * @memberof module:jiff-client~JIFFClient#SecretShare
   * @instance
   */
  SecretShare.prototype.neq = function (o, op_id) {
    if (this.isConstant(o)) {
      return this.cneq(o, op_id);
    }
    return this.sneq(o, op_id);
  };


  /**
   * Generic Integer Divison.
   * Uses either the constant or secret version of this operator depending on type of paramter.
   * @method div
   * @param {number|module:jiff-client~JIFFClient#SecretShare} o - the other operand (can be either number or share).
   * @param {number} l - the maximum bit length of the two shares.
   * @param {string} [op_id=auto_gen()] - the operation id which is used to identify this operation.
   *                         This id must be unique, and must be passed by all parties to the same instruction, to
   *                         ensure that corresponding instructions across different parties are matched correctly.
   * @return {module:jiff-client~JIFFClient#SecretShare} this party's share of the result.
   * @memberof module:jiff-client~JIFFClient#SecretShare
   * @instance
   */
  SecretShare.prototype.div = function (o, l, op_id) {
    if (this.isConstant(o)) {
      return this.cdiv(o, l, op_id);
    }
    return this.sdiv(o, l, op_id);
  };
};